package glmodel;

import java.io.*;
import java.util.ArrayList;
import ui.Message;

/**
 * Import a 3DS file into a GL_Model object.
 */
public class GL_3DS_Importer
{
	// Reads the 3DS files into vertex and face lists 
	private GL_3DS_Reader	reader	= new GL_3DS_Reader();

	// Mesh object will hold the data in a renderable form
	private GL_Mesh			mesh	= new GL_Mesh();

	public GL_3DS_Importer()
	{
	}

	public GL_Mesh load(String filename)
	{
		Message.getInstance().msg("GL_3DS_Importer.import(): Load object from " + filename);
		reader = new GL_3DS_Reader(filename);
		Message.getInstance().msg("GL_3DS_Importer.importFromStream(): model has " + reader.faces.size() + " faces and " + reader.vertices.size() + " vertices. ");
		return makeMeshObject(reader.vertices, reader.textureCoords, reader.normals, reader.faces);
	}

	/**
	 * create a GL_Object (mesh object) from the data read by a 3DS_Reader
	 * 
	 * @param verts
	 *            ArrayList of vertices
	 * @param txtrs
	 *            ArrayList of texture coordinates
	 * @param norms
	 *            ArrayList of normal
	 * @param faces
	 *            ArrayList of Face objects (triangles)
	 * @return
	 */
	public GL_Mesh makeMeshObject(ArrayList verts, ArrayList txtrs, ArrayList norms, ArrayList faces)
	{
		mesh = new GL_Mesh(); // mesh object
		mesh.name = "3DS";

		// add verts to GL_object
		for (int i = 0; i < verts.size(); i++)
		{
			float[] coords = (float[]) verts.get(i);
			mesh.addVertex(coords[0], coords[1], coords[2]);
		}

		// add triangles to GL_object.  3DS "face" is always a triangle.
		for (int i = 0; i < faces.size(); i++)
		{
			Face face = (Face) faces.get(i);
			// put verts, normals, texture coords into triangle
			addTriangle(mesh, face, txtrs, norms);
		}

		// optimize the GL_Object and generate normals
		mesh.rebuild();

		// if no normals were loaded, generate some
		if (norms.size() == 0)
		{
			mesh.regenerateNormals();
		}

		return mesh;
	}

	/**
	 * Add a new triangle to the GL_Object. This assumes that the vertices have
	 * already been added to the GL_Object, in the same order that they were in
	 * the 3DS.
	 * 
	 * @param obj
	 *            GL_Object
	 * @param face
	 *            a face from the OBJ file
	 * @param txtrs
	 *            ArrayList of texture coords from the OBJ file
	 * @param norms
	 *            ArrayList of normals from the OBJ file
	 * @param v1
	 *            vertices to use for the triangle (face may have >3 verts)
	 * @param v2
	 * @param v3
	 * @return
	 */
	public GL_Triangle addTriangle(GL_Mesh obj, Face face, ArrayList txtrs, ArrayList norms)
	{
		// An OBJ face may have many vertices (can be a polygon).  
		// Make a new triangle with the specified three verts.
		GL_Triangle t = new GL_Triangle(obj.vertex(face.vertexIDs[0]), obj.vertex(face.vertexIDs[1]), obj.vertex(face.vertexIDs[2]));

		// put texture coords into triangle
		if (txtrs.size() > 0)
		{ // if texture coords were loaded
			float[] uvw;
			uvw = (float[]) txtrs.get(face.textureIDs[0]); // txtr coord for vert 1
			t.uvw1 = new GL_Vector(uvw[0], uvw[1], uvw[2]);
			uvw = (float[]) txtrs.get(face.textureIDs[1]); // txtr coord for vert 2
			t.uvw2 = new GL_Vector(uvw[0], uvw[1], uvw[2]);
			uvw = (float[]) txtrs.get(face.textureIDs[2]); // txtr coord for vert 3
			t.uvw3 = new GL_Vector(uvw[0], uvw[1], uvw[2]);
		}

		// put normals into triangle (NOTE: normalID can be -1!!! could barf here!!!)
		if (norms.size() > 0)
		{ // if normals were loaded
			float[] norm;
			norm = (float[]) norms.get(face.normalIDs[0]); // normal for vert 1
			t.norm1 = new GL_Vector(norm[0], norm[1], norm[2]);
			norm = (float[]) norms.get(face.normalIDs[1]); // normal for vert 2
			t.norm2 = new GL_Vector(norm[0], norm[1], norm[2]);
			norm = (float[]) norms.get(face.normalIDs[2]); // normal for vert 3
			t.norm3 = new GL_Vector(norm[0], norm[1], norm[2]);
		}

		// add triangle to GL_object
		mesh.addTriangle(t);

		return t;
	}
}